package com.my.geojson.util;

import org.apache.commons.lang3.ArrayUtils;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;

import java.util.List;

/**
 * 空间对象的操作-- 创建 对比 判断
 */
public final class GeometryOptUtils {
    private static GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
    private static final double MISS_DISTANCE = 0.000002;

    /**
     * 经纬度 误差在 0.000002范围以内坐标时相等的
     */
    public static boolean isEquals(Coordinate coordinate1, Coordinate coordinate2) {
        return Math.abs(coordinate1.x - coordinate2.x) < MISS_DISTANCE &&
                Math.abs(coordinate1.y - coordinate2.y) < MISS_DISTANCE;
    }

    public static boolean isEquals(Geometry point1, Geometry point2) {
        if (point1.equals(point2)) {
            return true;
        }
        Coordinate coordinate1 = point1.getCoordinate();
        Coordinate coordinate2 = point2.getCoordinate();
        return isEquals(coordinate1, coordinate2);
    }
    public static Coordinate createCoordinate(double x, double y) {
        return new Coordinate(x, y);
    }

    public static Geometry createPoint(double x, double y) {
        return geometryFactory.createPoint(createCoordinate(x, y));
    }
    public static Geometry createPoint(Coordinate coordinate) {
        return geometryFactory.createPoint(coordinate);
    }
//    public Point createPointByWKT() throws ParseException, org.locationtech.jts.io.ParseException {
//        WKTReader reader = new WKTReader( geometryFactory );
//        Point point = (Point) reader.read("POINT (109.013388 32.715519)");
//        return point;
//    }
//    public MultiPoint createMulPointByWKT() throws ParseException, org.locationtech.jts.io.ParseException {
//        WKTReader reader = new WKTReader( geometryFactory );
//        MultiPoint mpoint = (MultiPoint) reader.read("MULTIPOINT(109.013388 32.715519,119.32488 31.435678)");
//        return mpoint;
//    }
    public static Geometry createLine(Coordinate coordinate1, Coordinate coordinate2) {
        Coordinate[] coords = new Coordinate[]{coordinate1, coordinate2};
        return geometryFactory.createLineString(coords);
    }
    public static Geometry createLine(Geometry point1, Geometry point2) {
        return createLine(point1.getCoordinate(), point2.getCoordinate());
    }
//    public LineString createLineByWKT() throws ParseException, org.locationtech.jts.io.ParseException {
//        WKTReader reader = new WKTReader( geometryFactory );
//        LineString line = (LineString) reader.read("LINESTRING(0 0, 2 0)");
//        return line;
//    }

    public static Geometry createLine(double x1, double y1, double x2, double y2) {
        Coordinate[] coords = new Coordinate[]{createCoordinate(x1, y1), createCoordinate(x2, y2)};
        return geometryFactory.createLineString(coords);
    }
    public static Geometry createLine(Coordinate coordinate) {
        Coordinate[] coords = new Coordinate[]{createCoordinate(0, 0), coordinate};
        return geometryFactory.createLineString(coords);
    }

    public static Geometry appendPoint(Geometry line, Geometry point) {
        Coordinate[] coordinates = ArrayUtils.add(line.getCoordinates(), point.getCoordinate());
        return geometryFactory.createLineString(coordinates);
    }
//    public MultiLineString createMLine(){
//        Coordinate[] coords1  = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};
//        LineString line1 = geometryFactory.createLineString(coords1);
//        Coordinate[] coords2  = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};
//        LineString line2 = geometryFactory.createLineString(coords2);
//        LineString[] lineStrings = new LineString[2];
//        lineStrings[0]= line1;
//        lineStrings[1] = line2;
//        MultiLineString ms = geometryFactory.createMultiLineString(lineStrings);
//        return ms;
//    }
//    public MultiLineString createMLineByWKT() throws ParseException, org.locationtech.jts.io.ParseException {
//        WKTReader reader = new WKTReader( geometryFactory );
//        MultiLineString line = (MultiLineString) reader.read("MULTILINESTRING((0 0, 2 0),(1 1,2 2))");
//        return line;
//    }

    /**
     * 根据几何对象数组，创建几何对象集合：【GeometryCollection】
     */
    public static GeometryCollection createGeoCollect(Geometry[] geoArray) {
        return geometryFactory.createGeometryCollection(geoArray);
    }
    /**
     * 获面
     * @param shellCoordinates 面边界坐标集合
     * @param holeCoordList 多个孔洞坐标集合
     * */
    public Polygon getPolygon(Coordinate [] shellCoordinates, List<Coordinate []> holeCoordList){
        LinearRing shell = geometryFactory.createLinearRing(shellCoordinates);
        LinearRing[] holes = new LinearRing[holeCoordList.size()];
        for(int m=0; m<holeCoordList.size(); m++){
            Coordinate [] holeCoordinates = holeCoordList.get(m);
            holes[m] = geometryFactory.createLinearRing(holeCoordinates);
        }
        return geometryFactory.createPolygon(shell, holes);
    }
    /**
     * 创建空多边形
     *
     * @return
     */
    public static Geometry createEmptyPolygon() {
        return geometryFactory.createPolygon();
    }
//    //构建多边形
//    public Polygon createPolygonByWKT() throws ParseException, org.locationtech.jts.io.ParseException {
//        WKTReader reader = new WKTReader( geometryFactory );
//        Polygon polygon = (Polygon) reader.read("POLYGON((20 10, 30 0, 40 10, 30 20, 20 10))");
//        return polygon;
//    }
//    public MultiPolygon createMulPolygonByWKT() throws ParseException, org.locationtech.jts.io.ParseException {
//        WKTReader reader = new WKTReader( geometryFactory );
//        MultiPolygon mpolygon = (MultiPolygon) reader.read("MULTIPOLYGON(((40 10, 30 0, 40 10, 30 20, 40 10),(30 10, 30 0, 40 10, 30 20, 30 10)))");
//        return mpolygon;
//    }

    /**
     * 根据多边形数组 进行多多边形的创建
     * @param polygons
     * @return
     * @throws ParseException
     */
    public MultiPolygon createMulPolygonByPolygon(Polygon[] polygons) throws ParseException {
        return geometryFactory.createMultiPolygon(polygons);
    }

//    //构建geo集合
//    public GeometryCollection createGeoCollect() throws ParseException, org.locationtech.jts.io.ParseException {
//        LineString line = createLine();
//        Polygon poly =  createPolygonByWKT();
//        Geometry g1 = geometryFactory.createGeometry(line);
//        Geometry g2 = geometryFactory.createGeometry(poly);
//        Geometry[] garray = new Geometry[]{g1,g2};
//        GeometryCollection gc = geometryFactory.createGeometryCollection(garray);
//        return gc;
//    }


//    //构建圆
//    public Polygon createCircle(double x, double y, final double RADIUS){
//        final int SIDES = 32;//圆上面的点个数
//        Coordinate coords[] = new Coordinate[SIDES+1];
//        for( int i = 0; i < SIDES; i++){
//            double angle = ((double) i / (double) SIDES) * Math.PI * 2.0;
//            double dx = Math.cos( angle ) * RADIUS;
//            double dy = Math.sin( angle ) * RADIUS;
//            coords[i] = new Coordinate( (double) x + dx, (double) y + dy );
//        }
//        coords[SIDES] = coords[0];
//        LinearRing ring = geometryFactory.createLinearRing( coords );
//        Polygon polygon = geometryFactory.createPolygon( ring, null );
//        return polygon;
//    }

    /**
     * 6.1 根据WKT创建环
     * @param ringWKT
     * @return
     * @throws ParseException
     */
    public LinearRing createLinearRingByWKT(String ringWKT) throws ParseException {
        WKTReader reader = new WKTReader( geometryFactory );
        return (LinearRing) reader.read(ringWKT);
    }

    /**
     * 将多个的图形进行合并 pg.union(pg1);
     *
     * @param polygons
     * @return
     */
    public static Geometry unionPolygon(List<Geometry> polygons) {
        Geometry[] pgs = polygons.toArray(new Geometry[polygons.size()]);
        GeometryCollection polygonCollection = geometryFactory.createGeometryCollection(pgs);
        Geometry union = polygonCollection.buffer(0);
        return union;
    }

    public static Geometry unionPolygon(Geometry... pgs) {
        GeometryCollection polygonCollection = geometryFactory.createGeometryCollection(pgs);
        Geometry union = polygonCollection.buffer(0);
        return union;
    }

    /**
     * 区域1是否包含区域2
     */
    public static boolean contain(Geometry geom1, Geometry geom2) {
        return geom1.intersects(geom2);
    }


    /**
     * 是线起点或终点
     */
    public static boolean isLineStartOrEndPoint(Geometry lineGeom, Geometry pointGeom) {
        LineString lineString = geometryFactory.createLineString(lineGeom.getCoordinates());
        return lineString.getStartPoint().equals(pointGeom) || lineString.getEndPoint().equals(pointGeom);
    }

    /**
     * 是线终点
     */
    public static boolean isLineEndPoint(Geometry lineGeom, Geometry pointGeom) {
        LineString lineString = geometryFactory.createLineString(lineGeom.getCoordinates());
        return lineString.getEndPoint().equals(pointGeom);
    }

    /**
     * 获取线终点
     */
    public static Geometry getLineEndPoint(Geometry lineGeom) {
        LineString lineString = geometryFactory.createLineString(lineGeom.getCoordinates());
        return lineString.getEndPoint();
    }


    /**
     *  两个几何对象是否是重叠的
     * @return
     * @throws ParseException
     */
    public static boolean equalsGeo() throws ParseException{
        WKTReader reader = new WKTReader( geometryFactory );
        LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
        LineString geometry2 = (LineString) reader.read("LINESTRING(5 0, 0 0)");
        return geometry1.equals(geometry2);//true
    }

    /**
     * 几何对象没有交点(相邻)
     * @return
     * @throws ParseException
     */
    public static boolean disjointGeo() throws ParseException{
        WKTReader reader = new WKTReader( geometryFactory );
        LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
        LineString geometry2 = (LineString) reader.read("LINESTRING(0 1, 0 2)");
        return geometry1.disjoint(geometry2);
    }

    /**
     * 至少一个公共点(相交)
     * @return
     * @throws ParseException
     */
    public static boolean intersectsGeo() throws ParseException{
        WKTReader reader = new WKTReader( geometryFactory );
        LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
        LineString geometry2 = (LineString) reader.read("LINESTRING(0 0, 0 2)");
        Geometry interPoint = geometry1.intersection(geometry2);//相交点
        System.out.println(interPoint.toText());//输出 POINT (0 0)
        return geometry1.intersects(geometry2);
    }

    /**
     * 判断以x,y为坐标的点point(x,y)是否在geometry表示的Polygon中
     * @param x
     * @param y
     * @param geometry wkt格式
     * @return
     */
    public static boolean withinGeo(double x,double y,String geometry) throws ParseException {

        Coordinate coord = new Coordinate(x,y);
        Point point = geometryFactory.createPoint( coord );

        WKTReader reader = new WKTReader( geometryFactory );
        Polygon polygon = (Polygon) reader.read(geometry);
        return point.within(polygon);
    }
    /**
     * @param args
     * @throws ParseException
     */
    public static void main(String[] args) throws ParseException {
        System.out.println(GeometryOptUtils.equalsGeo());
        System.out.println(GeometryOptUtils.disjointGeo());
        System.out.println(GeometryOptUtils.intersectsGeo());
        System.out.println(GeometryOptUtils.withinGeo(5,5,"POLYGON((0 0, 10 0, 10 10, 0 10,0 0))"));
    }
}
